﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using QLabValues;
using AtomicTypes;
using System.Text.RegularExpressions;

namespace NumericalCalculations
{
    public partial class Functions
    {

        public static QFloat64 bitmaxPow = new QFloat64(53);

        public static QFloat64 nameLengthMax = new QFloat64(63);

        public List<IQLabValue> namelengthmax(List<IQLabValue> o)
        {
            if (o.Count != 0)
                throw (new NumericalCalculationsException("??? Error using ==> namelengthmax \n Too many input arguments."));

            List<IQLabValue> res = new List<IQLabValue>();

            res.Add(new QFloat64NDimArray(new QFloat64[] { new QFloat64(nameLengthMax) }, new int[] { 1, 1 }));

            return res;
        }

        public List<IQLabValue> bitmax(List<IQLabValue> o)
        {
            // matlab vraca 2 na 53
            if (o.Count != 0)
                throw (new NumericalCalculationsException("??? Error using ==> bitmax \n Too many input arguments."));

            List<IQLabValue> res = new List<IQLabValue>();

            res.Add(new QFloat64NDimArray(new QFloat64[] { new QFloat64(Math.Pow(2, bitmaxPow.Real))}, new int[] { 1, 1 }));

            return res;
        }

        public List<IQLabValue> bitcmp(List<IQLabValue> o)
        {
            if (o.Count > 2)
                throw (new NumericalCalculationsException("??? Error using ==> bitcmp \n Too many input arguments."));

            if (o.Count < 1)
                throw (new NumericalCalculationsException("??? Error using ==> bitcmp \n Not enough input arguments."));

            if (o.Count == 1)
            {
                //proverimo da li su odgovarajuci tipovi
                IQLabValueType en = o.ElementAt(0).GetEnumType();
                if ((en != IQLabValueType.QUInt8NDimArray)
                        && (en != IQLabValueType.QUInt16NDimArray)
                            && (en != IQLabValueType.QUInt32NDimArray))
                {
                    //ukoliko je doube, provericu da li je svaki element ceo broj
                    if (en == IQLabValueType.QFloat64NDimArray)
                    {
                        throw (new NumericalCalculationsException("??? Error using ==> bitcmp \n Double operands to bitcmp require two inputs."));
                    }
                    else
                    {
                        throw (new NumericalCalculationsException("??? Undefined function or method 'bitcmp' for input arguments of type '" +
                        Helper.PrintEnumName(en) + "'."));
                    }
                }
                //matlab ne prijavljuje gresku ako je kompleksan, vec samo gleda realni deo

                //ako je uint8
                if (en == IQLabValueType.QUInt8NDimArray)
                {
                    QUInt8NDimArray qia = (QUInt8NDimArray)o.ElementAt(0);
                    QFloat64[] vals = new QFloat64[qia.Data.Count()];
                    for (int i = 0; i < vals.Count(); i++)
                    {
                        ushort x1 = qia.Data[i].Real;
                        vals[i] = new QFloat64(Math.Pow(2, 8) - 1 - x1);
                    }
                    QFloat64NDimArray qf = new QFloat64NDimArray(vals, qia.DimensionSize);
                    List<IQLabValue> res = new List<IQLabValue>();
                    res.Add(qf);
                    return res;
                }

                //ako je uint16
                if (en == IQLabValueType.QUInt16NDimArray)
                {
                    QUInt16NDimArray qia = (QUInt16NDimArray)o.ElementAt(0);
                    QFloat64[] vals = new QFloat64[qia.Data.Count()];
                    for (int i = 0; i < vals.Count(); i++)
                    {
                        ushort x1 = qia.Data[i].Real;
                        vals[i] = new QFloat64(Math.Pow(2, 16) - 1 - x1);
                    }
                    QFloat64NDimArray qf = new QFloat64NDimArray(vals, qia.DimensionSize);
                    List<IQLabValue> res = new List<IQLabValue>();
                    res.Add(qf);
                    return res;
                }

                //ako je uint32
                if (en == IQLabValueType.QUInt32NDimArray)
                {
                    QUInt32NDimArray qia = (QUInt32NDimArray)o.ElementAt(0);
                    QFloat64[] vals = new QFloat64[qia.Data.Count()];
                    for (int i = 0; i < vals.Count(); i++)
                    {
                        uint x1 = qia.Data[i].Real;
                        vals[i] = new QFloat64(Math.Pow(2, 32) - 1 - x1);
                    }
                    QFloat64NDimArray qf = new QFloat64NDimArray(vals, qia.DimensionSize);
                    List<IQLabValue> res = new List<IQLabValue>();
                    res.Add(qf);
                    return res;
                }

            }

            if (o.Count == 2)
            {
                //arg moze biti kao prethodno + double koji je ceo broj
                foreach (var el in o)
                {
                    IQLabValueType en = el.GetEnumType();
                    if ((en != IQLabValueType.QUInt8NDimArray)
                        && (en != IQLabValueType.QUInt16NDimArray)
                        && (en != IQLabValueType.QUInt32NDimArray))
                    {
                        //ukoliko je double, provericu da li je svaki element ceo broj
                        if (en == IQLabValueType.QFloat64NDimArray)
                        {
                            QFloat64NDimArray qf = new QFloat64NDimArray(el);
                            foreach (var q in qf.Data)
                            {
                                if (Helper.checkIfRealIsInt(q) == false)
                                    throw (new NumericalCalculationsException("??? Error using ==> bitcmp \n Inputs must be non-negative integers."));
                            }
                        }
                        else
                        {
                            throw (new NumericalCalculationsException("??? Undefined function or method 'bitcmp' for input arguments of type '" +
                            Helper.PrintEnumName(en) + "'."));
                        }
                    }
                }

                // proverili smo tipove tako da mozemo sve konvertovati u QFloat64NDimArray
                QFloat64NDimArray first = new QFloat64NDimArray(o.ElementAt(0));
                QFloat64NDimArray second = new QFloat64NDimArray(o.ElementAt(1));

                // drugi je ili skalar ili mora da ima iste dimenzije kao i prvi
                if(!Helper.checkIfScalar(second))
                {
                    if(!Helper.checkDimensions(first, second))
                        throw (new NumericalCalculationsException("??? Error using ==> bitcmp \n Inputs must have the same size."));

                    QFloat64[] vals = new QFloat64[first.Data.Count()];
                    QFloat64[] n = new QFloat64[first.Data.Count()];
                    for (int i = 0; i < vals.Count(); i++)
                    {
                        double x1 = first.Data[i].Real;
                        double x2 = second.Data[i].Real;
                        vals[i] = new QFloat64(Math.Pow(2, x2) - 1 - x1);
                        // ako je rezultat negativan onda je drugi argument premali
                        if (vals[i].Real < 0)
                            throw (new NumericalCalculationsException("??? Error using ==> bitcmp \n Values in" + Helper.PrintEnumName(o.ElementAt(0).GetEnumType()) + "should not have \"on\" bits in positions greater than N."));
                    }

                    QFloat64NDimArray qf = new QFloat64NDimArray(vals, first.DimensionSize);
                    List<IQLabValue> res = new List<IQLabValue>();
                    res.Add(qf);
                    return res;
                }
                else
                {
                    double scalar = second.Data[0].Real;

                    IQLabValueType en = o.ElementAt(0).GetEnumType();
                    // ako je skalar ne sme biti veci od tipa kojeg je prvi
                    if ((en == IQLabValueType.QUInt8NDimArray && scalar > 8) || (en == IQLabValueType.QUInt16NDimArray && scalar > 16) || (en == IQLabValueType.QUInt32NDimArray && scalar > 32))
                        throw (new NumericalCalculationsException("??? Error using ==> bitcmp \n The BIT argument to BITCMP must be a real scalar integer in the appropriate range."));

                    // ne sme da bude veci od bitmax(bitpow)
                    if(scalar > bitmaxPow.Real)
                        throw (new NumericalCalculationsException("??? Error using ==> bitcmp \n Exceeded value of bitmax."));

                    QFloat64[] vals = new QFloat64[first.Data.Count()];
                    for (int i = 0; i < vals.Count(); i++)
                    {
                        double x1 = first.Data[i].Real;
                        vals[i] = new QFloat64(Math.Pow(2, scalar) - 1 - x1);
                        // ako je rezultat negativan onda je drugi argument premali
                        if(vals[i].Real < 0)
                            throw (new NumericalCalculationsException("??? Error using ==> bitcmp \n Values in" + Helper.PrintEnumName(o.ElementAt(0).GetEnumType()) + "should not have \"on\" bits in positions greater than N."));
                    }

                    QFloat64NDimArray qf = new QFloat64NDimArray(vals, first.DimensionSize);
                    List<IQLabValue> res = new List<IQLabValue>();
                    res.Add(qf);

                    return res;
                }
            }

            return null;
        }

        public List<IQLabValue> bitget(List<IQLabValue> o)
        {
            if (o.Count < 2)
                throw (new NumericalCalculationsException("??? Error using ==> bitget \n Not enough input arguments."));
                
            if (o.Count > 2)
                throw (new NumericalCalculationsException("??? Error using ==> bitget \n Too many input arguments."));


            // provetavamo tipove argumenata
            foreach (var el in o)
            {
                IQLabValueType en = el.GetEnumType();
                if ((en != IQLabValueType.QUInt8NDimArray) && (en != IQLabValueType.QUInt16NDimArray) && (en != IQLabValueType.QUInt32NDimArray))
                {
                    //ukoliko je double, provericu da li je svaki element ceo broj
                    if (en == IQLabValueType.QFloat64NDimArray)
                        {
                            QFloat64NDimArray qf = new QFloat64NDimArray(el);
                            foreach (var q in qf.Data)
                            {
                                if (Helper.checkIfRealIsInt(q) == false)
                                {
                                    throw (new NumericalCalculationsException("??? Error using ==> bitget \n Inputs must be non-negative integers."));
                                }
                            }
                        }
                        else
                        {
                            throw (new NumericalCalculationsException("??? Error using ==> bitget \n Inputs must be non-negative integers."));
                        }
                }
            }

            // proverili smo tipove tako da mozemo sve konvertovati u QFloat64NDimArray
            QFloat64NDimArray first = new QFloat64NDimArray(o.ElementAt(0));
            QFloat64NDimArray second = new QFloat64NDimArray(o.ElementAt(1));

            ulong jedan = 1;

            // da li je drugi skalar ili nije?
            if (!Helper.checkIfScalar(second))
            {
                // drugi nije skalar, a da li je prvi?
                if (Helper.checkIfScalar(first))
                {
                    ulong firstScalar = (ulong)first.Data[0].Real;

                    QFloat64[] vals = new QFloat64[second.Data.Count()];

                    for (int i = 0; i < vals.Count(); i++)
                    {
                        int shiftBit = (int)second.Data[i].Real - 1;

                        var bit = firstScalar & (jedan << shiftBit);

                        if (bit != 0)
                            vals[i] = new QFloat64(1);
                        else
                            vals[i] = new QFloat64(0);
                    }

                    QFloat64NDimArray qf = new QFloat64NDimArray(vals, second.DimensionSize);
                    List<IQLabValue> res = new List<IQLabValue>();
                    res.Add(qf);

                    return res;
                }

                // ako ni jedan nije skalar onda moraju biti istih dimenzija
                if (!Helper.checkDimensions(first, second))
                    throw (new NumericalCalculationsException("??? Error using ==> bitget \n Inputs must have the same size."));
                else
                {
                    QFloat64[] vals = new QFloat64[first.Data.Count()];

                    for (int i = 0; i < vals.Count(); i++)
                    {
                        ulong x1 = (ulong)first.Data[i].Real;
                        int shiftBit = (int)second.Data[i].Real - 1;

                        var bit = x1 & (jedan << shiftBit);

                        if (bit != 0)
                            vals[i] = new QFloat64(1);
                        else
                            vals[i] = new QFloat64(0);
                    }

                    QFloat64NDimArray qf = new QFloat64NDimArray(vals, first.DimensionSize);
                    List<IQLabValue> res = new List<IQLabValue>();
                    res.Add(qf);
                    return res;
                }
            }
            else
            {
                int scalar = (int) second.Data[0].Real;

                IQLabValueType en = o.ElementAt(0).GetEnumType();

                // ako je skalar ne sme biti veci od tipa kojeg je prvi
                if ((en == IQLabValueType.QUInt8NDimArray && scalar > 8))
                    throw (new NumericalCalculationsException("??? Error using ==> bitget \n BIT must be integers between 1 and 8 for uint8."));

                if ((en == IQLabValueType.QUInt16NDimArray && scalar > 16))
                    throw (new NumericalCalculationsException("??? Error using ==> bitget \n BIT must be integers between 1 and 16 for uint16."));

                if ((en == IQLabValueType.QUInt16NDimArray && scalar > 32))
                    throw (new NumericalCalculationsException("??? Error using ==> bitget \n BIT must be integers between 1 and 32 for uint32."));

                // ne sme da bude veci ili jednak od bitmax(bitpow)
                if (scalar >= bitmaxPow.Real || scalar < 1)
                    throw (new NumericalCalculationsException("??? Error using ==> bitget \n BIT must be integers between 1 and 52 for double."));

                QFloat64[] vals = new QFloat64[first.Data.Count()];

                int shiftBit = scalar - 1;

                for (int i = 0; i < vals.Count(); i++)
                {
                    ulong x1 = (ulong) first.Data[i].Real;

                    var bit = x1 & (jedan << shiftBit);

                    if (bit != 0)
                        vals[i] = new QFloat64(1);
                    else
                        vals[i] = new QFloat64(0);
                }

                QFloat64NDimArray qf = new QFloat64NDimArray(vals, first.DimensionSize);
                List<IQLabValue> res = new List<IQLabValue>();
                res.Add(qf);

                return res;
            }
        }

        public List<IQLabValue> bitset(List<IQLabValue> o)
        {
            if (o.Count < 2)
                throw (new NumericalCalculationsException("??? Error using ==> bitset \n Not enough input arguments."));

            if (o.Count > 3)
                throw (new NumericalCalculationsException("??? Error using ==> bitset \n Too many input arguments."));

            // proverimo tipove za prva dva argumenta
            for (int i = 0; i < 2; i++)
            {
                IQLabValueType en = o.ElementAt(i).GetEnumType();
                if ((en != IQLabValueType.QUInt8NDimArray) && (en != IQLabValueType.QUInt16NDimArray) && (en != IQLabValueType.QUInt32NDimArray))
                {
                    //ukoliko je double, provericu da li je svaki element ceo broj
                    if (en == IQLabValueType.QFloat64NDimArray)
                    {
                        QFloat64NDimArray qf = new QFloat64NDimArray(o.ElementAt(i));
                        foreach (var q in qf.Data)
                        {
                            if (Helper.checkIfRealIsInt(q) == false)
                            {
                                throw (new NumericalCalculationsException("??? Error using ==> bitset \n Inputs must be non-negative integers."));
                            }
                        }
                    }
                    else
                    {
                        throw (new NumericalCalculationsException("??? Error using ==> bitset \n Inputs must be non-negative integers."));
                    }
                }
            }

            // proverili smo tipove tako da mozemo sve konvertovati u QFloat64NDimArray
            QFloat64NDimArray first = new QFloat64NDimArray(o.ElementAt(0));
            QFloat64NDimArray second = new QFloat64NDimArray(o.ElementAt(1));
            QFloat64NDimArray third;

            // napravimo treci argument bez obzira da li on stvarno postoji
            QFloat64[] thirdVals;
            int[] dimensionSize;
            if (!Helper.checkIfScalar(first))
            {
                thirdVals = new QFloat64[first.Data.Count()];
                dimensionSize = first.DimensionSize;
            }
            else
            {
                thirdVals = new QFloat64[second.Data.Count()];
                dimensionSize = second.DimensionSize;
            }

            for (int i = 0; i < thirdVals.Count(); i++)
                thirdVals[i] = new QFloat64(1);

            third = new QFloat64NDimArray(thirdVals, dimensionSize);

            // ako ima tri argumenta
            if (o.Count == 3)
            {
                // proverimo da li moze da se konvertuje u QFloat64NDimArray
                if (Helper.canConvertToEnum(o.ElementAt(2), IQLabValueType.QFloat64NDimArray))
                    third = new QFloat64NDimArray(o.ElementAt(2));
                else
                    throw (new NumericalCalculationsException("??? Error using ==> bitset Inputs must be non-negative integers."));
            }

            // ako neka nije skalar moramo da proverimo dimenzije
            if (!Helper.checkIfScalar(first) || !Helper.checkIfScalar(second) || !Helper.checkIfScalar(third))
            {
                if (o.Count == 3)
                {
                    // ako su bar dvema dimenzije iste onda je sve ok
                    if (!(Helper.checkDimensions(first, second) || Helper.checkDimensions(first, third) || Helper.checkDimensions(third, second)))
                        throw (new NumericalCalculationsException("??? Error using ==> bitset \n Inputs must have the same size."));
                }
                else
                {
                    if (!(Helper.checkDimensions(first, second)))
                        throw (new NumericalCalculationsException("??? Error using ==> bitset \n Inputs must have the same size."));
                }
            }

            // proverimo granice za drugi argument
            IQLabValueType enumType = o.ElementAt(1).GetEnumType();
            for (int i = 0; i < second.Data.Count(); i++)
            {
                int x = (int)second.Data.ElementAt(i).Real;

                // ako je skalar ne sme biti veci od tipa kojeg je prvi
                if ((enumType == IQLabValueType.QUInt8NDimArray && x > 8))
                    throw (new NumericalCalculationsException("??? Error using ==> bitset \n BIT must be integers between 1 and 8 for uint8."));

                if ((enumType == IQLabValueType.QUInt16NDimArray && x > 16))
                    throw (new NumericalCalculationsException("??? Error using ==> bitset \n BIT must be integers between 1 and 16 for uint16."));

                if ((enumType == IQLabValueType.QUInt16NDimArray && x > 32))
                    throw (new NumericalCalculationsException("??? Error using ==> bitset \n BIT must be integers between 1 and 32 for uint32."));

                // ne sme da bude veci ili jednak od bitmax(bitpow)
                if (x >= bitmaxPow.Real || x < 1)
                    throw (new NumericalCalculationsException("??? Error using ==> bitset \n BIT must be integers between 1 and 52 for double."));
            }

            // skaliramo sve na velicinu najveceg
            QFloat64NDimArray firstPrim;
            QFloat64NDimArray secondPrim;
            QFloat64NDimArray thirdPrim;

            // odredimo max dimenziju
            int max = first.Data.Count();
            int[] dimension = first.DimensionSize;

            if (max < second.Data.Count())
            {
                max = second.Data.Count();
                dimension = second.DimensionSize;
            }
            if (max < third.Data.Count())
            {
                max = third.Data.Count();
                dimension = third.DimensionSize;
            }

            QFloat64[] firstPrimVals = new QFloat64[max];
            QFloat64[] secondPrimVals = new QFloat64[max];
            QFloat64[] thirdPrimVals = new QFloat64[max];

            if (Helper.checkIfScalar(first))
            {
                double firstScalar = first.Data.ElementAt(0).Real;

                for (int i = 0; i < max; i++)
                    firstPrimVals[i] = new QFloat64(firstScalar);

                firstPrim = new QFloat64NDimArray(firstPrimVals, dimension);
            }
            else
            {
                firstPrim = first;
            }


            if (Helper.checkIfScalar(second))
            {
                double secondScalar = second.Data.ElementAt(0).Real;

                for (int i = 0; i < max; i++)
                    secondPrimVals[i] = new QFloat64(secondScalar);

                secondPrim = new QFloat64NDimArray(secondPrimVals, dimension);
            }
            else
            {
                secondPrim = second;
            }

            if (o.Count == 3)
            {

                if (Helper.checkIfScalar(third))
                {
                    double thirdScalar = third.Data.ElementAt(0).Real;

                    for (int i = 0; i < max; i++)
                        thirdPrimVals[i] = new QFloat64(thirdScalar);

                    thirdPrim = new QFloat64NDimArray(thirdPrimVals, dimension);
                }
                else
                {
                    thirdPrim = third;
                }
            }
            else
            {
                for (int i = 0; i < max; i++)
                    thirdPrimVals[i] = new QFloat64(1);

                thirdPrim = new QFloat64NDimArray(thirdPrimVals, dimension);
            }

            // sada bez obzira koliko ima argumenata racunamo sa sve tri matrice
            QFloat64[] vals = new QFloat64[firstPrim.Data.Count()];

            for (int i = 0; i < vals.Count(); i++)
            {
                long x1 = (long)firstPrim.Data[i].Real;

                int shiftBit = (int)secondPrim.Data[i].Real - 1;

                long maska = 1;
                maska = maska << shiftBit;

                // znaci da postavljamo bit na 1, a u else na 0
                if (thirdPrim.Data[i].Real != 0)
                {
                    vals[i] = new QFloat64(x1 | maska);
                }
                else
                {
                    maska = (long)~maska;
                    vals[i] = new QFloat64(x1 & maska);
                }
            }

            QFloat64NDimArray qfa = new QFloat64NDimArray(vals, firstPrim.DimensionSize);
            List<IQLabValue> res = new List<IQLabValue>();
            res.Add(qfa);
            return res;
        }

        public List<IQLabValue> bitshift(List<IQLabValue> o)
        {
            if (o.Count < 2)
                throw (new NumericalCalculationsException("??? Error using ==> bitshift \n Not enough input arguments."));

            if (o.Count > 3)
                throw (new NumericalCalculationsException("??? Error using ==> bitshift \n Too many input arguments."));

            // proverimo tipove za prvi argument
            IQLabValueType en = o.ElementAt(0).GetEnumType();
            if ((en != IQLabValueType.QUInt8NDimArray) && (en != IQLabValueType.QUInt16NDimArray) && (en != IQLabValueType.QUInt32NDimArray))
            {
                //ukoliko je double, provericu da li je svaki element ceo broj
                if (en == IQLabValueType.QFloat64NDimArray)
                {
                    QFloat64NDimArray qf = new QFloat64NDimArray(o.ElementAt(0));
                    foreach (var q in qf.Data)
                    {
                        // NE RADI DOBRO checkIfRealIsInt PITAJ DARKA ZASTO, STA RADITI?
                        if (Helper.checkIfRealIsInt(q) == false)
                        {
                            throw (new NumericalCalculationsException("??? Error using ==> bitshift \n Inputs must be non-negative integers."));
                        }
                    }
                }
                else
                {
                    throw (new NumericalCalculationsException("??? Error using ==> bitset \n Inputs must be non-negative integers."));
                }
            }

            // proverimo tipove za drugi argument
            IQLabValueType en1 = o.ElementAt(1).GetEnumType();
            if ((en1 != IQLabValueType.QUInt8NDimArray) && (en1 != IQLabValueType.QUInt16NDimArray) && (en1 != IQLabValueType.QUInt32NDimArray) && (en1 != IQLabValueType.QInt16NDimArray) && (en1 != IQLabValueType.QInt32NDimArray) && (en1 != IQLabValueType.QInt8NDimArray))
            {
                //ukoliko je double, provericu da li je svaki element ceo broj
                if (en1 == IQLabValueType.QFloat64NDimArray)
                {
                    QFloat64NDimArray qf = new QFloat64NDimArray(o.ElementAt(1));
                    foreach (var q in qf.Data)
                    {
                        // NE RADI DOBRO checkIfRealIsInt PITAJ DARKA ZASTO, STA RADITI?
                        if (Helper.checkIfRealIsInt(q) == false)
                        {
                            throw (new NumericalCalculationsException("??? Error using ==> bitshift \n Inputs must be integers."));
                        }
                    }
                }
                else
                {
                    throw (new NumericalCalculationsException("??? Error using ==> bitshift \n Inputs must be  integers."));
                }
            }

            // proverili smo tipove tako da mozemo sve konvertovati u QFloat64NDimArray
            QFloat64NDimArray first = new QFloat64NDimArray(o.ElementAt(0));
            QFloat64NDimArray second = new QFloat64NDimArray(o.ElementAt(1));
            QFloat64NDimArray third;

            // napravimo treci argument u odnosu na tip prvog
            QFloat64[] thirdVals;
            int[] dimensionSize;

            int n = 0;
            IQLabValueType en2 = o.ElementAt(0).GetEnumType();
            if (en2 == IQLabValueType.QInt8NDimArray)
                n = 8;
            if (en2 == IQLabValueType.QInt16NDimArray)
                n = 16;
            if (en2 == IQLabValueType.QInt32NDimArray || en2 == IQLabValueType.QFloat32NDimArray)
                n = 32;
            if (en2 == IQLabValueType.QInt64NDimArray || en2 == IQLabValueType.QFloat64NDimArray)
                n = 64;

            if (!Helper.checkIfScalar(first))
            {
                thirdVals = new QFloat64[first.Data.Count()];
                dimensionSize = first.DimensionSize;
            }
            else
            {
                thirdVals = new QFloat64[second.Data.Count()];
                dimensionSize = second.DimensionSize;
            }

            for (int i = 0; i < thirdVals.Count(); i++)
                thirdVals[i] = new QFloat64(n);

            third = new QFloat64NDimArray(thirdVals, dimensionSize);

            // ako ima tri argumenta
            if (o.Count == 3)
            {
                // proverimo da li moze da se konvertuje u QFloat64NDimArray
                if (Helper.canConvertToEnum(o.ElementAt(2), IQLabValueType.QFloat64NDimArray))
                    third = new QFloat64NDimArray(o.ElementAt(2));
                else
                    throw (new NumericalCalculationsException("??? Error using ==> bitset Inputs must be non-negative integers."));
            }

            // ako neka nije skalar moramo da proverimo dimenzije
            if (!Helper.checkIfScalar(first) || !Helper.checkIfScalar(second) || !Helper.checkIfScalar(third))
            {
                if (o.Count == 3)
                {
                    // ako su bar dvema dimenzije iste onda je sve ok
                    if (!(Helper.checkDimensions(first, second) || Helper.checkDimensions(first, third) || Helper.checkDimensions(third, second)))
                        throw (new NumericalCalculationsException("??? Error using ==> bitset \n Inputs must have the same size."));
                }
                else
                {
                    if (!(Helper.checkDimensions(first, second)))
                        throw (new NumericalCalculationsException("??? Error using ==> bitset \n Inputs must have the same size."));
                }
            }

            // skaliramo na velicinu najveceg
            QFloat64NDimArray firstPrim;
            QFloat64NDimArray secondPrim;
            QFloat64NDimArray thirdPrim;

            // odredimo max dimenziju
            int max = first.Data.Count();
            int[] dimension = first.DimensionSize;

            if (max < second.Data.Count())
            {
                max = second.Data.Count();
                dimension = second.DimensionSize;
            }
            if (max < third.Data.Count())
            {
                max = third.Data.Count();
                dimension = third.DimensionSize;
            }

            QFloat64[] firstPrimVals = new QFloat64[max];
            QFloat64[] secondPrimVals = new QFloat64[max];
            QFloat64[] thirdPrimVals = new QFloat64[max];

            if (Helper.checkIfScalar(first))
            {
                double firstScalar = first.Data.ElementAt(0).Real;

                for (int i = 0; i < max; i++)
                    firstPrimVals[i] = new QFloat64(firstScalar);

                firstPrim = new QFloat64NDimArray(firstPrimVals, dimension);
            }
            else
            {
                firstPrim = first;
            }


            if (Helper.checkIfScalar(second))
            {
                double secondScalar = second.Data.ElementAt(0).Real;

                for (int i = 0; i < max; i++)
                    secondPrimVals[i] = new QFloat64(secondScalar);

                secondPrim = new QFloat64NDimArray(secondPrimVals, dimension);
            }
            else
            {
                secondPrim = second;
            }

            if (o.Count == 3)
            {

                if (Helper.checkIfScalar(third))
                {
                    double thirdScalar = third.Data.ElementAt(0).Real;

                    for (int i = 0; i < max; i++)
                        thirdPrimVals[i] = new QFloat64(thirdScalar);

                    thirdPrim = new QFloat64NDimArray(thirdPrimVals, dimension);
                }
                else
                {
                    thirdPrim = third;
                }
            }
            else
            {
                thirdPrim = third;
            }

            // sada bez obzira koliko ima argumenata racunamo sa sve tri matrice
            QFloat64[] vals = new QFloat64[firstPrim.Data.Count()];

            for (int i = 0; i < vals.Count(); i++)
            {
                ulong x1 = (ulong)firstPrim.Data[i].Real;

                int x2 = (int)secondPrim.Data[i].Real;

                int x3 = (int)thirdPrim.Data[i].Real;

                double val;

                if (x3 - x2 > 1024)
                {
                    // ovako vraca matlab
                    val = double.NaN;
                }
                else
                {
                    if (x2 > 0)
                    {
                        // ovako radi matlab!!!
                        if (x2 >= bitmaxPow.Real)
                        {
                            val = 0;
                        }
                        else
                        {
                            val = x1 << x2;
                        }

                    }
                    else if (x2 < 0)
                    {
                        val = x1 >> (-x2);
                    }
                    else
                    {
                        val = x1;
                    }

                    // siftovali smo, sada odsecemo visak
                    if (x3 > 0)
                    {
                        ulong maska = 1;

                        for (int j = 1; j < x3; j++)
                        {
                            maska = maska << 1;
                            maska = maska + 1;
                        }

                        val = ((ulong)val) & maska;
                    }
                    else
                    {
                        val = 0;
                    }
                }

                vals[i] = new QFloat64(val);
            }

            QFloat64NDimArray qfa = new QFloat64NDimArray(vals, firstPrim.DimensionSize);
            List<IQLabValue> res = new List<IQLabValue>();
            res.Add(qfa);
            return res;
        }

        //Nije dovrsena, treba implementirati cell i struct
        public List<IQLabValue> ctranspose(List<IQLabValue> o)
        {
            if (o.Count > 1)
                throw (new NumericalCalculationsException("??? Error using ==> ctranspose \n Too many input arguments."));

            if (o.Count < 1)
                throw (new NumericalCalculationsException("??? Error using ==> ctranspose \n Not enough input arguments."));

            if (Helper.canConvertListToEnum(o, IQLabValueType.QFloat64NDimArray))
            {
                //konvertujem u float64
                List<QFloat64NDimArray> of = new List<QFloat64NDimArray>();
                foreach (var oel in o)
                    of.Add(new QFloat64NDimArray(oel));

                //pravim novi niz
                QFloat64[] vals = new QFloat64[of.ElementAt(0).Data.Count()];
                for (int i = 0; i < vals.Count(); i++)
                {
                    double x1 = of.ElementAt(0).Data[i].Real;
                    double y1 = of.ElementAt(0).Data[i].Imag;
                    vals[i] = new QFloat64(x1, -y1);
                }

                //dodajem u listu i vracam
                //transponujem i vracam
                List<IQLabValue> args = new List<IQLabValue>();
                args.Add(new QFloat64NDimArray(vals, of.ElementAt(0).DimensionSize));
                return transpose(args);
            }

            else
            // nije uspelo konvertovanje, znaci da su vrednosti cell, struct ...
            {
                //TODO: IMLEMENTIRAJ za CELL i STRUCT...
                throw (new NumericalCalculationsException("NOT IMPLEMENTED YET!!!"));
            }

        }

        public List<IQLabValue> transpose(List<IQLabValue> o)
        {
            if (o.Count > 1)
                throw (new NumericalCalculationsException("??? Error using ==> transpose \n Too many input arguments."));

            if (o.Count < 1)
                throw (new NumericalCalculationsException("??? Error using ==> transpose \n Not enough input arguments."));

            //ukoliko je char
            if (o.ElementAt(0).GetEnumType() == IQLabValueType.QCharNDimArray)
            {
                QCharNDimArray qca = new QCharNDimArray(o.ElementAt(0));
                //pogledamo da li ima manje od dve dimenzije
                if ((qca.Dimension > 2) || (qca.Dimension < 2))
                    throw (new NumericalCalculationsException("??? Error using ==> transpose \n Transpose on ND array is not defined."));
                QCharNDimArray q = new QCharNDimArray(new int[] { qca.DimensionSize[1], qca.DimensionSize[0] });

                //popunimo i vratimo
                for (int i = 0; i < qca.DimensionSize[0]; i++)
                    for (int j = 0; j < qca.DimensionSize[1]; j++)
                        q[j, i] = new QChar(qca[i, j]);
                List<IQLabValue> res = new List<IQLabValue>();
                res.Add(q);
                return res;
            }

            //ukoliko je int64
            if (o.ElementAt(0).GetEnumType() == IQLabValueType.QInt64NDimArray)
            {
                QInt64NDimArray qia = new QInt64NDimArray(o.ElementAt(0));
                //pogledamo da li ima manje od dve dimenzije
                if ((qia.Dimension > 2) || (qia.Dimension < 2))
                    throw (new NumericalCalculationsException("??? Error using ==> transpose Transpose on ND array is not defined."));
                QInt64NDimArray q = new QInt64NDimArray(new int[] { qia.DimensionSize[1], qia.DimensionSize[0] });

                //popunimo i vratimo
                for (int i = 0; i < qia.DimensionSize[0]; i++)
                    for (int j = 0; j < qia.DimensionSize[1]; j++)
                        q[j, i] = new QInt64(qia[i, j]);
                List<IQLabValue> res = new List<IQLabValue>();
                res.Add(q);
                return res;
            }

            //ukoliko je Qfloat
            if (Helper.canConvertListToEnum(o, IQLabValueType.QFloat64NDimArray))
            {
                QFloat64NDimArray qia = new QFloat64NDimArray(o.ElementAt(0));
                //pogledamo da li ima manje od dve dimenzije
                if ((qia.Dimension > 2) || (qia.Dimension < 2))
                    throw (new NumericalCalculationsException("??? Error using ==> transpose Transpose on ND array is not defined."));
                QFloat64NDimArray q = new QFloat64NDimArray(new int[] { qia.DimensionSize[1], qia.DimensionSize[0] });

                //popunimo i vratimo
                for (int i = 0; i < qia.DimensionSize[0]; i++)
                    for (int j = 0; j < qia.DimensionSize[1]; j++)
                        q[j, i] = new QFloat64(qia[i, j]);
                List<IQLabValue> res = new List<IQLabValue>();
                res.Add(q);
                return res;
            }

            //ukoliko je Qbool
            if (Helper.canConvertListToEnum(o, IQLabValueType.QBooleanNDimArray))
            {
                QBooleanNDimArray qia = new QBooleanNDimArray(o.ElementAt(0));
                //pogledamo da li ima manje od dve dimenzije
                if ((qia.Dimension > 2) || (qia.Dimension < 2))
                    throw (new NumericalCalculationsException("??? Error using ==> transpose Transpose on ND array is not defined."));
                QFloat64NDimArray q = new QFloat64NDimArray(new int[] { qia.DimensionSize[1], qia.DimensionSize[0] });

                //popunimo i vratimo
                for (int i = 0; i < qia.DimensionSize[0]; i++)
                    for (int j = 0; j < qia.DimensionSize[1]; j++)
                        q[j, i] = new QFloat64(qia[i, j]);
                List<IQLabValue> res = new List<IQLabValue>();
                res.Add(q);
                return res;
            }

            // ukoliko je QCell
            if (Helper.canConvertListToEnum(o, IQLabValueType.QCell))
            {
                QCell qia = new QCell(o.ElementAt(0));
                //pogledamo da li ima manje od dve dimenzije
                if ((qia.Dimension > 2) || (qia.Dimension < 2))
                    throw (new NumericalCalculationsException("??? Error using ==> transpose Transpose on ND array is not defined."));
                QCell q = new QCell(new int[] { qia.DimensionSize[1], qia.DimensionSize[0] });

                //popunimo i vratimo
                for (int i = 0; i < qia.DimensionSize[0]; i++)
                    for (int j = 0; j < qia.DimensionSize[1]; j++)
                    {
                        // proveravamo sve tipove
                        if (Helper.canConvertToEnum(qia[i, j], IQLabValueType.QBooleanNDimArray))
                        {
                            q[j, i] = new QBooleanNDimArray(qia[i, j]);
                        }
                        else if (Helper.canConvertToEnum(qia[i, j], IQLabValueType.QCharNDimArray))
                        {
                            q[j, i] = new QCharNDimArray(qia[i, j]);
                        }
                        else if (Helper.canConvertToEnum(qia[i, j], IQLabValueType.QCell))
                        {
                            q[j, i] = new QCell(qia[i, j]);
                        }
                        else if (Helper.canConvertToEnum(qia[i, j], IQLabValueType.QFloat64NDimArray))
                        {
                            q[j, i] = new QFloat64NDimArray(qia[i, j]);
                        }
                        else if (Helper.canConvertToEnum(qia[i, j], IQLabValueType.QInt64NDimArray))
                        {
                            q[j, i] = new QInt64NDimArray(qia[i, j]);
                        }
                        else if (Helper.canConvertToEnum(qia[i, j], IQLabValueType.QStructValueNDimArray))
                        {
                            q[j, i] = new QStructValueNDimArray(qia[i, j]);
                        }
                        else
                        {
                            throw (new NumericalCalculationsException("??? Error using ==> transpose Some types are not defined."));
                        }
                    }
                List<IQLabValue> res = new List<IQLabValue>();
                res.Add(q);
                return res;
            }

            //ukoliko je QStruct
            if (Helper.canConvertListToEnum(o, IQLabValueType.QStructValueNDimArray))
            {
                QStructValueNDimArray qia = new QStructValueNDimArray(o.ElementAt(0));

                //pogledamo da li ima manje od dve dimenzije
                if ((qia.Dimension > 2) || (qia.Dimension < 2))
                    throw (new NumericalCalculationsException("??? Error using ==> transpose Transpose on ND array is not defined."));
                QStructValueNDimArray q = new QStructValueNDimArray(new int[] { qia.DimensionSize[1], qia.DimensionSize[0] });

                //popunimo i vratimo
                for (int i = 0; i < qia.DimensionSize[0]; i++)
                    for (int j = 0; j < qia.DimensionSize[1]; j++)
                    {
                        // q[j, i] = new QFloat64(qia[i, j]);
                    }
                List<IQLabValue> res = new List<IQLabValue>();
                res.Add(q);
                return res;
            }

            throw (new NumericalCalculationsException("??? Error using ==> transpose Some inner types are wrong."));
        }

        public List<IQLabValue> nan(List<IQLabValue> o)
        {
            if (o.Count == 0)
            {
                List<IQLabValue> res = new List<IQLabValue>();
                QFloat64NDimArray q = new QFloat64NDimArray(1, 1);

                q[0, 0] = new QFloat64(double.NaN);

                res.Add(q);

                return res;
            }

            if (o.Count == 1)
            {
                if (Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCharNDimArray))
                {
                    QCharNDimArray qca = new QCharNDimArray(o.ElementAt(0));

                    List<string> stringList = Helper.QCharNDimArrayToStringList(qca);

                    if (stringList.Count > 1)
                    {
                        throw (new NumericalCalculationsException("??? Error using ==> Inf \n Leading inputs must be numeric."));
                    }

                    if (!(stringList.ElementAt(0).Equals("single") || stringList.ElementAt(0).Equals("double")))
                    {
                        throw (new NumericalCalculationsException("??? Error using ==> Inf \n Trailing string input must be 'single' or 'double'."));
                    }
                    else
                    {
                        List<IQLabValue> res = new List<IQLabValue>();
                        QFloat64NDimArray q = new QFloat64NDimArray(1, 1);

                        q[0, 0] = new QFloat64(double.NaN);

                        res.Add(q);

                        return res;
                    }
                }
                else if (Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QFloat64NDimArray))
                {
                    QFloat64NDimArray qia = new QFloat64NDimArray(o.ElementAt(0));

                    int dim = (int)qia[0, 0].Real;

                    List<IQLabValue> res = new List<IQLabValue>();
                    QFloat64NDimArray q = new QFloat64NDimArray(dim, dim);

                    for (int i = 0; i < dim; i++)
                    {
                        for (int j = 0; j < dim; j++)
                        {
                            q[i, j] = new QFloat64(double.NaN);
                        }
                    }

                    res.Add(q);

                    return res;
                }
                else
                {
                    throw (new NumericalCalculationsException("??? Error using ==> Inf \n Inputs must be numeric."));
                }
            }

            /*if (o.Count > 2)
            {
                if (Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QInt64NDimArray))
                {
                    QInt64NDimArray qia = new QInt64NDimArray(o.ElementAt(0));
                    
                    // dimension size
                    
                    int[] dimensionSize = qia.

                    int dim = (int)qia[0, 0].Real;

                    List<IQLabValue> res = new List<IQLabValue>();
                    QFloat64NDimArray q = new QFloat64NDimArray(dim, dim);

                    for (int i = 0; i < dim; i++)
                    {
                        for (int j = 0; j < dim; j++)
                        {
                            q[i, j] = new QFloat64(double.PositiveInfinity);
                        }
                    }

                    res.Add(q);

                    return res;
                }
            }*/

            return null;
        }

        public List<IQLabValue> isvector(List<IQLabValue> o)
        {
            if (o.Count < 1)
            {
                throw (new NumericalCalculationsException("??? Error using ==> isvector Not enough input arguments."));
            }
            else if (o.Count > 1)
            {
                throw (new NumericalCalculationsException("??? Error using ==> isvector Too many input arguments."));
            }
            else
            {
                if (Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QFloat64NDimArray))
                {
                    QFloat64NDimArray qia = new QFloat64NDimArray(o.ElementAt(0));

                    List<IQLabValue> res = new List<IQLabValue>();
                    QFloat64NDimArray q = new QFloat64NDimArray(1, 1);

                    if (qia.Dimension > 2)
                    {
                        q[0, 0] = new QFloat64(0);
                        res.Add(q);

                        return res;
                    }
                    else
                    {
                        if ((qia.DimensionSize[0] != 1) && (qia.DimensionSize[1] != 1))
                        {
                            q[0, 0] = new QFloat64(0);
                            res.Add(q);

                            return res;
                        }
                        else
                        {
                            q[0, 0] = new QFloat64(1);
                            res.Add(q);

                            return res;
                        }
                    }
                }
                else
                {
                    throw (new NumericalCalculationsException("??? Undefined function or method 'isvector' for input arguments of type " + o.ElementAt(0).GetEnumType() + "."));
                }
            }
        }

        public List<IQLabValue> iscell(List<IQLabValue> o)
        {
            if (o.Count < 1)
            {
                throw (new NumericalCalculationsException("??? Error using ==> iscell Not enough input arguments."));
            }
            else if (o.Count > 1)
            {
                throw (new NumericalCalculationsException("??? Error using ==> iscell Too many input arguments."));
            }
            else
            {
                List<IQLabValue> res = new List<IQLabValue>();
                QFloat64NDimArray q = new QFloat64NDimArray(1, 1);

                if (Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCell))
                {


                    q[0, 0] = new QFloat64(1);
                    res.Add(q);

                    return res;
                }
                else
                {
                    q[0, 0] = new QFloat64(0);
                    res.Add(q);

                    return res;
                }
            }
        }

        public List<IQLabValue> isstruct(List<IQLabValue> o)
        {
            if (o.Count < 1)
            {
                throw (new NumericalCalculationsException("??? Error using ==> isstruct Not enough input arguments."));
            }
            else if (o.Count > 1)
            {
                throw (new NumericalCalculationsException("??? Error using ==> isstruct Too many input arguments."));
            }
            else
            {
                List<IQLabValue> res = new List<IQLabValue>();
                QFloat64NDimArray q = new QFloat64NDimArray(1, 1);

                if (Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QStructValueNDimArray))
                {


                    q[0, 0] = new QFloat64(1);
                    res.Add(q);

                    return res;
                }
                else
                {
                    q[0, 0] = new QFloat64(0);
                    res.Add(q);

                    return res;
                }
            }
        }

        public List<IQLabValue> isvarname(List<IQLabValue> o)
        {
            if (o.Count < 1)
            {
                throw (new NumericalCalculationsException("??? Error using ==> isvarname Not enough input arguments."));
            }
            else if (o.Count > 1)
            {
                throw (new NumericalCalculationsException("??? Error using ==> isvarname Too many input arguments."));
            }
            else
            {
                if (Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCharNDimArray))
                {
                    QCharNDimArray qca = new QCharNDimArray(o.ElementAt(0));

                    List<string> s = Helper.QCharNDimArrayToStringList(qca);

                    if (s.Count > 1)
                    {
                        throw (new NumericalCalculationsException("??? Error using ==> isvarname Too many input arguments."));
                    }

                    string varname = s.ElementAt(0);

                    List<IQLabValue> res = new List<IQLabValue>();
                    QFloat64NDimArray q = new QFloat64NDimArray(1, 1);

                    //validacija
                    // duzina
                    if (varname.Count() > nameLengthMax.Real)
                    {
                        q[0, 0] = new QFloat64(0);
                        res.Add(q);

                        return res;
                    }

                    // da li je prvi char slovo
                    if (!Char.IsLetter(varname.ElementAt(0)))
                    {
                        q[0, 0] = new QFloat64(0);
                        res.Add(q);

                        return res;
                    }

                    //karakteri
                    for (int i = 0; i < varname.Count(); i++)
                    {
                        if (!(Char.IsLetterOrDigit(varname.ElementAt(i)) || varname.ElementAt(i) == '_'))
                        {
                            q[0, 0] = new QFloat64(0);
                            res.Add(q);

                            return res;
                        }
                    }

                    q[0, 0] = new QFloat64(1);
                    res.Add(q);

                    return res;
                }
                else
                {
                    throw (new NumericalCalculationsException("??? Undefined function or method 'isvarname' for input arguments of type " + o.ElementAt(0).GetEnumType() + "."));
                }
            }
        }

        public List<IQLabValue> isa(List<IQLabValue> o)
        {
            if (o.Count < 2)
            {
                throw (new NumericalCalculationsException("??? Error using ==> isa Not enough input arguments."));
            }
            else if (o.Count > 2)
            {
                throw (new NumericalCalculationsException("??? Error using ==> isa Too many input arguments."));
            }
            else
            {
                if (Helper.canConvertToEnum(o.ElementAt(1), IQLabValueType.QCharNDimArray))
                {
                    QCharNDimArray qca = new QCharNDimArray(o.ElementAt(1));

                    List<string> s = Helper.QCharNDimArrayToStringList(qca);

                    if (s.Count > 1)
                    {
                        throw (new NumericalCalculationsException("??? Error using ==> isvarname Too many input arguments."));
                    }

                    string varname = s.ElementAt(0);

                    List<IQLabValue> res = new List<IQLabValue>();
                    QFloat64NDimArray q = new QFloat64NDimArray(1, 1);

                    if (varname.Equals("logical") && Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QBooleanNDimArray))
                    {
                        q[0, 0] = new QFloat64(1);
                        res.Add(q);
                        return res;
                    }

                    if (varname.Equals("char") && Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCharNDimArray))
                    {
                        q[0, 0] = new QFloat64(1);
                        res.Add(q);
                        return res;
                    }

                    if ((varname.Equals("single") || varname.Equals("double") || varname.Equals("float")) && Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QFloat64NDimArray))
                    {
                        q[0, 0] = new QFloat64(1);
                        res.Add(q);
                        return res;
                    }


                    if ((varname.Equals("int8") || varname.Equals("uint8") || varname.Equals("int16") || varname.Equals("uint16") || varname.Equals("int32") || varname.Equals("uint32") || varname.Equals("int64") || varname.Equals("uint64")) && Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QInt64NDimArray))
                    {
                        q[0, 0] = new QFloat64(1);
                        res.Add(q);
                        return res;
                    }

                    if (varname.Equals("cell") && Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCell))
                    {
                        q[0, 0] = new QFloat64(1);
                        res.Add(q);
                        return res;
                    }

                    if (varname.Equals("struct") && Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QStructValueNDimArray))
                    {
                        q[0, 0] = new QFloat64(1);
                        res.Add(q);
                        return res;
                    }

                    // ako nije prosao ni jedan if vrati false
                    q[0, 0] = new QFloat64(0);
                    res.Add(q);
                    return res;
                }
                else
                {
                    throw (new NumericalCalculationsException("??? Undefined function or method 'isvarname' for input arguments of type " + o.ElementAt(0).GetEnumType() + "."));
                }
            }
        }

        public List<IQLabValue> inf(List<IQLabValue> o)
        {
            if (o.Count == 0)
            {
                List<IQLabValue> res = new List<IQLabValue>();
                QFloat64NDimArray q = new QFloat64NDimArray(1,1);
                
                q[0,0] = new QFloat64(double.PositiveInfinity);
                
                res.Add(q);

                return res;
            }

            if (o.Count == 1)
            {
                if(Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCharNDimArray)) {
                    QCharNDimArray qca = new QCharNDimArray(o.ElementAt(0));
                    
                    List<string> stringList = Helper.QCharNDimArrayToStringList(qca);

                    if (stringList.Count > 1)
                    {
                        throw (new NumericalCalculationsException("??? Error using ==> Inf \n Leading inputs must be numeric."));
                    }

                    if (!(stringList.ElementAt(0).Equals("single") || stringList.ElementAt(0).Equals("double")))
                    {
                        throw (new NumericalCalculationsException("??? Error using ==> Inf \n Trailing string input must be 'single' or 'double'."));
                    }
                    else
                    {
                        List<IQLabValue> res = new List<IQLabValue>();
                        QFloat64NDimArray q = new QFloat64NDimArray(1, 1);

                        q[0, 0] = new QFloat64(double.PositiveInfinity);

                        res.Add(q);

                        return res;
                    }
                }
                else if (Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QFloat64NDimArray))
                {
                    QFloat64NDimArray qia = new QFloat64NDimArray(o.ElementAt(0));

                    int dim = (int)qia[0, 0].Real;

                    List<IQLabValue> res = new List<IQLabValue>();
                    QFloat64NDimArray q = new QFloat64NDimArray(dim, dim);

                    for (int i = 0; i < dim; i++)
                    {
                        for (int j = 0; j < dim; j++)
                        {
                            q[i, j] = new QFloat64(double.PositiveInfinity);
                        }
                    }

                    res.Add(q);

                    return res;
                }
                else
                {
                    throw (new NumericalCalculationsException("??? Error using ==> Inf \n Inputs must be numeric."));
                }
            }

            return null;
        }

        public List<IQLabValue> regexp(List<IQLabValue> o)
        {
            if (o.Count < 2)
            {
                throw (new NumericalCalculationsException("??? Error using ==> regexp \n Not enough input arguments."));
            }

            if (o.Count > 2)
            {
                throw (new NumericalCalculationsException("??? Error using ==> regexp \n Too many input arguments."));
            }

            if (!(Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCharNDimArray) && (Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCharNDimArray))))
            {
                throw (new NumericalCalculationsException("??? Undefined function or method 'regex' for input arguments of type " + o.ElementAt(0).GetEnumType() + " and " + o.ElementAt(0).GetEnumType() + " ."));
            }

            QCharNDimArray qca1 = (QCharNDimArray)o.ElementAt(0);
            QCharNDimArray qca2 = (QCharNDimArray)o.ElementAt(1);

            string str = Helper.QCharNDimArrayToStringList(qca1).ElementAt(0);
            string pattern = Helper.QCharNDimArrayToStringList(qca2).ElementAt(0);

            Regex reg = new Regex(pattern);

            MatchCollection matches = reg.Matches(str);

            QFloat64NDimArray qf = new QFloat64NDimArray(matches.Count, 1);

            for (int i = 0; i < matches.Count; i++)
            {
                qf[i, 0] = new QFloat64(matches[i].Index);
            }

            List<IQLabValue> res = new List<IQLabValue>();

            res.Add(qf);

            return res;
        }

        public List<IQLabValue> regexpi(List<IQLabValue> o)
        {
            if (o.Count < 2)
            {
                throw (new NumericalCalculationsException("??? Error using ==> regexp \n Not enough input arguments."));
            }

            if (o.Count > 2)
            {
                throw (new NumericalCalculationsException("??? Error using ==> regexp \n Too many input arguments."));
            }

            if (!(Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCharNDimArray) && (Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCharNDimArray))))
            {
                throw (new NumericalCalculationsException("??? Undefined function or method 'regex' for input arguments of type " + o.ElementAt(0).GetEnumType() + " and " + o.ElementAt(0).GetEnumType() + " ."));
            }

            QCharNDimArray qca1 = (QCharNDimArray)o.ElementAt(0);
            QCharNDimArray qca2 = (QCharNDimArray)o.ElementAt(1);

            string str = Helper.QCharNDimArrayToStringList(qca1).ElementAt(0);
            string pattern = Helper.QCharNDimArrayToStringList(qca2).ElementAt(0);

            Regex reg = new Regex(pattern, RegexOptions.IgnoreCase);

            MatchCollection matches = reg.Matches(str);

            QFloat64NDimArray qf = new QFloat64NDimArray(matches.Count, 1);

            for (int i = 0; i < matches.Count; i++)
            {
                qf[i, 0] = new QFloat64(matches[i].Index);
            }

            List<IQLabValue> res = new List<IQLabValue>();

            res.Add(qf);

            return res;
        }
    }
}
